package com.example.security;

import cn.hutool.core.util.StrUtil;
import com.example.common.constant.Const;
import com.example.common.exception.UserStatusException;
import com.example.service.IUserService;
import com.example.util.JwtUtil;
import com.example.util.RedisUtil;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwtException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;

//Jwt认证过滤器
public class JwtAuthenticationFilter extends BasicAuthenticationFilter {

    @Autowired
    JwtUtil jwtUtil;

    @Autowired
    RedisUtil redisUtil;

    @Autowired
    IUserService userService;

    @Autowired
    MyUserDetailsService myUserDetailsService;

    public JwtAuthenticationFilter(AuthenticationManager authenticationManager) {
        super(authenticationManager);
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {

        String jwt = request.getHeader(jwtUtil.getHeader());
        if (StrUtil.isBlankOrUndefined(jwt)) {
            //请求头不含jwt时，跳过Jwt认证，过滤器链继续往后走
            chain.doFilter(request, response);
            return;
        }
        //解析jwt
        Claims claim = jwtUtil.getClaimByToken(jwt);
        if (claim == null) {
            throw new JwtException("token异常");
        }

        // 若token未被篡改，则获取token里面的用户信息
        String userName = claim.getSubject();

        // 判断token状态
        if (redisUtil.hasKey(Const.PREFIX_JWT+userName)){
            if (!redisUtil.get(Const.PREFIX_JWT+userName).equals(jwt)) {
                redisUtil.del(Const.PREFIX_JWT+userName);
                throw new JwtException("token失效");
            }
        }else {
            throw new JwtException("token失效");
        }

        // 通过userName获取对应的权限信息和状态信息
        MyUserDetails userDetails;
        userDetails = userService.getUserDetailsByUserName(userName);

        // 若用户状态异常，阻止用户继续访问其他接口
        if (!userDetails.isStatus()) {
            throw new UserStatusException("用户状态异常");
        }
        List<GrantedAuthority> authorities = myUserDetailsService.getUserAuthority(userName);
        UsernamePasswordAuthenticationToken token
                = new UsernamePasswordAuthenticationToken(userName, userDetails.getPassword(), authorities);

        //通过security完成用户自动登录
        SecurityContextHolder.getContext().setAuthentication(token);
        //过滤器链继续往后
        chain.doFilter(request, response);

    }
}
